library flutter_datetime_picker;


import 'package:base_flutter/src/widget/timePicker/date_model.dart';
import 'package:base_flutter/src/widget/timePicker/datetime_picker_theme.dart';
import 'package:base_flutter/src/widget/timePicker/i18n_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

typedef DateChangedCallback(DateTime? time);
typedef String? StringAtIndexCallBack(int index);

class DatePicker {
  ///
  /// Display date picker bottom sheet.
  ///
  static void showDatePicker(
    BuildContext context, {
    bool showTitleActions: true,
    DateTime? minTime,
    DateTime? maxTime,
    String title = "",
        TextStyle? titleStyle,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    locale: LocaleType.zh,
    DateTime? currentTime,
    DateTimePickerTheme? theme,
  }) {
    Navigator.push(
        context,
        new _DatePickerRoute(
            showTitleActions: showTitleActions,
            onChanged: onChanged,
            onConfirm: onConfirm,
            locale: locale,
            theme: theme,
            barrierLabel:
                MaterialLocalizations.of(context).modalBarrierDismissLabel,
            pickerModel: DatePickerModel(
                currentTime: currentTime,
                maxTime: maxTime,
                minTime: minTime,
                locale: locale)));
  }

  static void showMonthPicker(
      BuildContext context, {
        bool showTitleActions: true,
        DateTime? minTime,
        DateTime? maxTime,
        String title = "",
        TextStyle? titleStyle,
        DateChangedCallback? onChanged,
        DateChangedCallback? onConfirm,
        locale: LocaleType.zh,
        DateTime? currentTime,
        DateTimePickerTheme? theme,
      }) {
    Navigator.push(
        context,
        new _DatePickerRoute(
            showTitleActions: showTitleActions,
            onChanged: onChanged,
            onConfirm: onConfirm,
            locale: locale,
            theme: theme,
            barrierLabel:
            MaterialLocalizations.of(context).modalBarrierDismissLabel,
            pickerModel: MonthPickerModel(
                currentTime: currentTime,
                maxTime: maxTime,
                minTime: minTime,
                locale: locale)));
  }



  ///
  /// Display time picker bottom sheet.
  ///
  static void showTimePicker(
    BuildContext context, {
    bool showTitleActions: true,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    locale: LocaleType.zh,
    DateTime? currentTime,
        String title = '',
        TextStyle? titleStyle,
    DateTimePickerTheme? theme,
  }) {
    Navigator.push(
        context,
        new _DatePickerRoute(
            showTitleActions: showTitleActions,
            onChanged: onChanged,
            onConfirm: onConfirm,
            locale: locale,
            theme: theme,

            barrierLabel:
                MaterialLocalizations.of(context).modalBarrierDismissLabel,
            pickerModel:
                TimePickerModel(currentTime: currentTime, locale: locale)));
  }

  ///
  /// Display date&time picker bottom sheet.
  ///
  static void showDateTimePicker(
    BuildContext context, {
    bool showTitleActions: true,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    locale: LocaleType.zh,
    DateTime? currentTime,
        String title="",
        TextStyle? titleStyle,
    DateTimePickerTheme? theme,
  }) {
    Navigator.push(
        context,
        new _DatePickerRoute(
            showTitleActions: showTitleActions,
            onChanged: onChanged,
            onConfirm: onConfirm,
            locale: locale,
            theme: theme,
            barrierLabel:
                MaterialLocalizations.of(context).modalBarrierDismissLabel,
            pickerModel:
                DateTimePickerModel(currentTime: currentTime, locale: locale)));
  }

  ///
  /// Display date picker bottom sheet witch custom picker model.
  ///
  static void showPicker(
    BuildContext context, {
    bool showTitleActions: true,
    DateChangedCallback? onChanged,
    DateChangedCallback? onConfirm,
    locale: LocaleType.zh,
        String title = "",
        TextStyle? titleStyle,
    BasePickerModel? pickerModel,
    DateTimePickerTheme? theme,
  }) {
    Navigator.push(
        context,
        new _DatePickerRoute(
            showTitleActions: showTitleActions,
            onChanged: onChanged,
            onConfirm: onConfirm,
            locale: locale,
            theme: theme,

            barrierLabel:
                MaterialLocalizations.of(context).modalBarrierDismissLabel,
            pickerModel: pickerModel));
  }
}

class _DatePickerRoute<T> extends PopupRoute<T> {
  _DatePickerRoute({
    this.showTitleActions = true,

    this.onChanged,
    this.onConfirm,
    theme,
    this.barrierLabel = "",
    this.locale,
    RouteSettings? settings,
    pickerModel,
  })  : this.pickerModel = pickerModel ?? DatePickerModel(),
        this.theme = theme ?? DateTimePickerTheme(),
        super(settings: settings);

  final bool showTitleActions;
  final DateChangedCallback? onChanged;
  final DateChangedCallback? onConfirm;
  final DateTimePickerTheme? theme;
  final LocaleType? locale;
  final BasePickerModel? pickerModel;


  @override
  Duration get transitionDuration => const Duration(milliseconds: 200);

  @override
  bool get barrierDismissible => true;

  @override
  final String barrierLabel;

  @override
  Color get barrierColor => Colors.black54;

  AnimationController? _animationController;

  @override
  AnimationController createAnimationController() {
    assert(_animationController == null);
    _animationController =
        BottomSheet.createAnimationController(navigator!.overlay!);
    return _animationController!;
  }

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    Widget bottomSheet = new MediaQuery.removePadding(
      context: context,
      removeTop: true,
      child: _DatePickerComponent(
        onChanged: onChanged,
        locale: this.locale??LocaleType.zh,
        route: this,
        pickerModel: pickerModel!,
      ),
    );
    ThemeData inheritTheme = Theme.of(context);
    if (inheritTheme != null) {
      bottomSheet = new Theme(data: inheritTheme, child: bottomSheet);
    }
    return bottomSheet;
  }
}

class _DatePickerComponent extends StatefulWidget {
  _DatePickerComponent(
      {Key? key,
      required this.route,
      this.onChanged,
      this.locale,
      this.pickerModel});

  final DateChangedCallback? onChanged;

  final _DatePickerRoute route;

  final LocaleType? locale;

  final BasePickerModel? pickerModel;

  @override
  State<StatefulWidget> createState() {
    return _DatePickerState();
  }
}

class _DatePickerState extends State<_DatePickerComponent> {
  FixedExtentScrollController? leftScrollCtrl, middleScrollCtrl, rightScrollCtrl;

  @override
  void initState() {
    super.initState();
    refreshScrollOffset();
  }

  void refreshScrollOffset() {
    leftScrollCtrl = new FixedExtentScrollController(
        initialItem: widget.pickerModel!.currentLeftIndex());
    middleScrollCtrl = new FixedExtentScrollController(
        initialItem: widget.pickerModel!.currentMiddleIndex());
    rightScrollCtrl = new FixedExtentScrollController(
        initialItem: widget.pickerModel!.currentRightIndex());
  }

  @override
  Widget build(BuildContext context) {
    DateTimePickerTheme? theme = widget.route.theme;
    return new GestureDetector(
      child: new AnimatedBuilder(
        animation: widget.route.animation!,
        builder: (BuildContext context, Widget? child) {
          return new ClipRect(
            child: new CustomSingleChildLayout(
              delegate: new _BottomPickerLayout(
                  widget.route.animation!.value, theme!,
                  showTitleActions: widget.route.showTitleActions),
              child: new GestureDetector(
                child: Material(
                  color: Colors.transparent,
                  child: _renderPickerView(theme),
                ),
              ),
            ),
          );
        },
      ),
    );
  }

  void _notifyDateChanged() {
    if (widget.onChanged != null) {
      widget.onChanged!(widget.pickerModel!.finalTime());
    }
  }

  Widget _renderPickerView(DateTimePickerTheme theme) {
    Widget itemView = _renderItemView(theme);
    if (widget.route.showTitleActions) {
      return Column(
        children: <Widget>[
          _renderTitleActionsView(theme),
          itemView,
        ],
      );
    }
    return itemView;
  }

  Widget _renderColumnView(
      ValueKey key,
      DateTimePickerTheme theme,
      StringAtIndexCallBack stringAtIndexCB,
      FixedExtentScrollController scrollController,
      int layoutProportion,
      ValueChanged<int> selectedChangedWhenScrolling,
      ValueChanged<int>? selectedChangedWhenScrollEnd) {
    return Expanded(
      flex: layoutProportion,
      child: Container(
          padding: EdgeInsets.all(8.0),
          height: theme.containerHeight,
          decoration:
              BoxDecoration(color: theme.backgroundColor ?? Colors.white),
          child: NotificationListener(
              onNotification: (ScrollNotification notification) {
                if (notification.depth == 0 &&
                    selectedChangedWhenScrollEnd != null &&
                    notification is ScrollEndNotification &&
                    notification.metrics is FixedExtentMetrics) {
                  final FixedExtentMetrics metrics = notification.metrics as FixedExtentMetrics;
                  final int currentItemIndex = metrics.itemIndex;
                  selectedChangedWhenScrollEnd(currentItemIndex);
                }
                return false;
              },
              child: CupertinoPicker.builder(
                  key: key,
                  backgroundColor: theme.backgroundColor ?? Colors.white,
                  scrollController: scrollController,
                  itemExtent: theme.itemHeight,
                  onSelectedItemChanged: (int index) {
                    selectedChangedWhenScrolling(index);
                  },
                  useMagnifier: true,
                  itemBuilder: (BuildContext context, int index) {
                    final content = stringAtIndexCB(index);
                    if (content == null) {
                      return null;
                    }
                    return Container(
                      height: theme.itemHeight,
                      alignment: Alignment.center,
                      child: Text(
                        content,
                        style: theme.itemStyle,
                        textAlign: TextAlign.start,
                      ),
                    );
                  }))),
    );
  }

  Widget _renderItemView(DateTimePickerTheme theme) {
    return Container(
      color: theme.backgroundColor ?? Colors.white,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          _renderColumnView(
              ValueKey(widget.pickerModel?.currentLeftIndex()),
              theme,
              widget.pickerModel!.leftStringAtIndex,
              leftScrollCtrl!,
              widget.pickerModel!.layoutProportions()[0], (index) {
            widget.pickerModel!.setLeftIndex(index);
          }, (index) {
            setState(() {
              refreshScrollOffset();
              _notifyDateChanged();
            });
          }),
          Text(
            widget.pickerModel?.leftDivider()??"",
            style: theme.itemStyle,
          ),
          _renderColumnView(
              ValueKey(widget.pickerModel?.currentLeftIndex()),
              theme,
              widget.pickerModel!.middleStringAtIndex,
              middleScrollCtrl!,
              widget.pickerModel!.layoutProportions()[1], (index) {
            widget.pickerModel?.setMiddleIndex(index);
          }, (index) {
            setState(() {
              refreshScrollOffset();
              _notifyDateChanged();
            });
          }),
          Text(
            widget.pickerModel?.rightDivider()??"",
            style: theme.itemStyle,
          ),
          _renderColumnView(
              ValueKey(widget.pickerModel!.currentMiddleIndex() +
                  widget.pickerModel!.currentLeftIndex()),
              theme,
              widget.pickerModel!.rightStringAtIndex,
              rightScrollCtrl!,
              widget.pickerModel!.layoutProportions()[2], (index) {
            widget.pickerModel!.setRightIndex(index);
            _notifyDateChanged();
          }, null),
        ],
      ),
    );
  }

  // Title View
  Widget _renderTitleActionsView(DateTimePickerTheme theme) {
    String done = _localeDone();
    String cancel = _localeCancel();

    return Container(
      height: theme.titleHeight,
      decoration: BoxDecoration(color: theme.backgroundColor ?? Colors.white),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Container(
            height: theme.titleHeight,
            child: CupertinoButton(
              pressedOpacity: 0.3,
              padding: EdgeInsets.only(left: 16, top: 0),
              child: Text(
                '$cancel',
                style: theme.cancelStyle,
              ),
              onPressed: () => Navigator.pop(context),
            ),
          ),
          Text(theme.title!=null?theme.title:"请选择",
          style: theme.titleStyle!=null?theme.titleStyle:TextStyle(color: Colors.black,fontSize: 18),),
          Container(
            height: theme.titleHeight,
            child: CupertinoButton(
              pressedOpacity: 0.3,
              padding: EdgeInsets.only(right: 16, top: 0),
              child: Text(
                '$done',
                style: theme.doneStyle,
              ),
              onPressed: () {
                Navigator.pop(context);
                if (widget.route.onConfirm != null) {
                  widget.route.onConfirm!(widget.pickerModel!.finalTime());
                }
              },
            ),
          ),
        ],
      ),
    );
  }

  String _localeDone() {
    return i18nObjInLocale(widget.locale!)!['done'];
  }

  String _localeCancel() {
    return i18nObjInLocale(widget.locale!)!['cancel'];
  }
}

class _BottomPickerLayout extends SingleChildLayoutDelegate {
  _BottomPickerLayout(this.progress, this.theme,
      {this.itemCount, this.showTitleActions = true});

  final double progress;
  final int? itemCount;
  final bool showTitleActions;
  final DateTimePickerTheme theme;

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    double maxHeight = theme.containerHeight;
    if (showTitleActions) {
      maxHeight += theme.titleHeight;
    }

    return new BoxConstraints(
        minWidth: constraints.maxWidth,
        maxWidth: constraints.maxWidth,
        minHeight: 0.0,
        maxHeight: maxHeight);
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    double height = size.height - childSize.height * progress;
    return new Offset(0.0, height);
  }

  @override
  bool shouldRelayout(_BottomPickerLayout oldDelegate) {
    return progress != oldDelegate.progress;
  }
}
